<script lang="ts">
export default {
  name: 'Study4StuDemo1'
}
</script>

<template>
  <h2>响应式工具</h2>
  <div class="note">
    <p>1. isRef()：检查某个值是否为 ref</p>
    <p>(1) 注：返回值是一个类型判定，即 isRef 可以被用作类型守卫</p>
    <p>(2) 注：isRef()直接在模板字符串中使用不生效，需要在 setup() 中使用，并用computed()中接收</p>
  </div>
  <div class="note">
    <p>2. unref()：解除 ref 包装</p>
    <p>(1) 如果参数是 ref，则返回内部值，否则返回参数本身</p>
    <p>(2) 简化访问：unref 常用于直接获取其原始值，而不需要手动访问 .value</p>
    <p>(3) 处理嵌套结构：在复杂的嵌套结构中，使用 unref 可以避免重复访问 .value</p>
    <p>
      (4) 在计算属性和侦听器中使用：在使用计算属性和侦听器时，unref 可以使对 ref
      的访问更直接，避免额外的 .value
    </p>
    <p>
      (5) 支持普通值和 ref：unref 可以处理普通值和
      ref，这使得函数可以接收这两种类型的参数，增强了灵活性
    </p>
  </div>
  <div class="note">
    <p>3. toRef(): 将对象中的属性转换为 ref</p>
    <p>(1) 将对象中的属性转换为 ref，可以使得属性的值变成响应式的</p>
    <p>(2) toRef()可以接收两个参数：对象和属性名</p>
    <p>(3) toRef的值不同于ref的值，ref()接收到的是一个纯数值，toRef()的响应式状态会与原始值同步</p>
  </div>
  <div class="note">
    <p>4. toValue(): 将 ref 转换为普通值</p>
    <p>(1) 将 ref 转换为普通值，可以使得 ref 的值变成非响应式的</p>
    <p>(2) toValue()可以接收一个参数：ref</p>
  </div>
  <div class="note">
    <p>5. toRefs(): 将对象中的所有属性转换为 ref</p>
    <p>(1) 将对象中的所有属性转换为 ref，可以使得属性的值变成响应式的</p>
    <p>(2) toRefs()可以接收一个参数：对象</p>
    <p>(3) 将响应式对象的属性转换为独立的响应式引用。这使得在解构对象时仍能保持响应性</p>
  </div>
  <div class="note">
    <p>6. isProxy()：检查某个值是否为代理对象, 即是否是由 reactive()、readonly()、shallowReactive() 或 shallowReadonly() 创建的代理</p>
    <p>(1) 创建的响应式对象会返回 true，而普通对象则返回 false。</p>
  </div>
  <div class="note">
    <p>7. isReactive()：检查某个值是否为 reactive 对象, 即是否是由 reactive() 或 shallowReactive() 创建的代理</p>
    <p>(1) 返回 true 表示该对象是响应式的，返回 false 则表示不是</p>
  </div>
  <div class="note">
    <p>8. isReadonly()：检查某个值是否为只读 ref</p>
    <p>(1) 通过 readonly() 和 shallowReadonly() 创建的代理都是只读的，因为他们是没有 set 函数的 computed() ref</p>
  </div>







  <hr class="hr-style" />
  <h3>isRef()</h3>
  <div class="test">
    <!-- 错误示范：在模板字符串中使用 -->
    <!-- <p>isRef(isRef_no): {{ isRef(isRef_no) }}</p>
    <p>isRef(isRef_yes): {{ isRef(isRef_yes) }}</p> -->
    <div>
      <p>1. 直接用变量接收</p>
      <p>no:{{ no }}</p>
      <p>yes:{{ yes }}</p>
    </div>
    <div>
      <p>2. computed()接收【规范书写】</p>
      <p>isRef_no_computed:{{ isRef_no_computed }}</p>
      <p>isRef_yes_computed:{{ isRef_yes_computed }}</p>
    </div>
  </div>

  <hr class="hr-style" />
  <h3>unref()</h3>
  <div class="test">
    <div>
      <p>1. computed()接收</p>
      <p>unref_no_computed:{{ unref_no_computed }}</p>
      <p>unref_yes_computed:{{ unref_yes_computed }}</p>
    </div>
    <div>
      <p>2. 定义变量时直接用unref获取值，无需.value访问</p>
      <p>currentCount:{{ currentCount }}</p>
    </div>
    <!-- <div>
      <p>3. 处理嵌套结构</p>
      <p>value:{{ value }}</p>
      <p>value2:{{ value2 }}</p>
    </div> -->
    <div>
      <p>3. 在计算属性和侦听器中使用</p>
      <p>computedCount:{{ computedCount }}</p>
    </div>
    <div>
      <p>4. 支持普通值和 ref</p>
      <p>{{ printValue(100) }}</p>
      <p>{{ printValue(ref(200)) }}</p>
      <p>{{ printValue(reactive({ 123: 456 })) }}</p>
    </div>
  </div>

  <hr class="hr-style" />
  <h3>toRef()</h3>
  <div class="test">
    <div>
      <p>obj.a:{{ obj.a }}</p>
      <p @click="obj.a++">objToRef:{{ objToRef }}</p>
      <p @click="objToRef++">objToRef:{{ objToRef }}</p>
    </div>
    <div>
      <p @click="commonValue++">commonValue:{{ commonValue }}</p>
      <p @click="comToRef++">comToRef:{{ comToRef }}</p>
    </div>
  </div>

  <hr class="hr-style" />
  <h3>toValue()</h3>
  <div class="test">
    <div>
      <p @click="data++">data:{{ data }}</p>
      <p @click="dataToValue++">dataToValue:{{ dataToValue }}</p>
    </div>
  </div>

  <hr class="hr-style" />
  <h3>toRefs()</h3>
  <div class="test">
    <div>
      <p @click="state.count++">state:{{ state }}</p>
      <!-- toRefs 会将 reactive 对象的每个属性转换为一个引用(ref)，所以 stateToRefs.count 实际上是一个引用对象，而不是直接的数字。 -->
      <p @click="stateToRefs.count.value++">stateToRefs:{{ stateToRefs }}</p>
      
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, isRef, unref, reactive, computed, toRef, toValue, toRefs, isProxy, isReactive,readonly, isReadonly } from 'vue'

// isRef()
const isRef_no = reactive({ 123: 456 })
const isRef_yes = ref({ 456: 888 })

const no = isRef(isRef_no) // false
const yes = isRef(isRef_yes) // true

// 正确示范：在 setup() 中使用，并用computed()中接收
const isRef_no_computed = computed(() => isRef(isRef_no))
const isRef_yes_computed = computed(() => isRef(isRef_yes))

// unref()
const unref_no = reactive({ 123: 456 })
const unref_yes = ref(456)

const unref_no_computed = computed(() => unref(unref_no))
const unref_yes_computed = computed(() => unref(unref_yes))

const count = ref(0)
const currentCount = unref(count)

// const nestedRef = ref({data: ref(10)})
// const value = unref(nestedRef.value.data)
// const value2 = nestedRef.value.data
// console.log(value, value2);

const computedCount = computed(() => unref(count))

function printValue(normalValue: any) {
  return unref(normalValue)
}

// toRef()
const obj = reactive({ a: 1, b: 2 })
const objToRef = toRef(obj, 'a')

const commonValue = 100
const comToRef = toRef(commonValue)

// toValue()
const data = ref(10)
const dataToValue = toValue(data)

// toRefs()
const state = reactive({
  count: 0,
  message: 'Hello'
});
const stateToRefs = toRefs(state);

// isProxy()
const state1 = reactive({
  count: 0
});
console.log(isProxy(state1)); // 输出 true
const plainObject = { count: 0 };
console.log(isProxy(plainObject)); // 输出 false

// isReactive()
const state2 = reactive({
  count: 0
});
console.log(isReactive(state2)); // 输出 true
const plainObject2 = { count: 0 };
console.log(isReactive(plainObject2)); // 输出 false

// isReadonly()
const state3 = readonly({
  count: 0
});
console.log(isReadonly(state3)); // 输出 true
const plainObject3 = { count: 0 };
console.log(isReadonly(plainObject3)); // 输出 false
</script>

<style scoped>
body {
  padding: 20px;
}
h2 {
  color: red;
}
h3 {
  color: rgb(220, 85, 85);
}
h4 {
  color: skyblue;
}
.hr-style {
  border: 3px solid gold;
  margin: 20px 0;
}
.note {
  margin: 10px;
  padding: 10px;
  border: 3px solid rgb(221, 121, 202);
}
.note p {
  color: rgb(226, 106, 204);
  font-weight: bold;
}
</style>
